home *** CD-ROM | disk | FTP | other *** search
- # Copyright (c) 2003-2006 CORE Security Technologies
- #
- # This software is provided under under a slightly modified version
- # of the Apache Software License. See the accompanying LICENSE file
- # for more information.
- #
- # $Id: ntlm.py,v 1.2 2006/05/23 21:19:25 gera Exp $
- #
-
- from impacket.structure import Structure
- try:
- from Crypto.Cipher import DES
- from Crypto.Hash import MD4
- POW = None
- except Exception:
- try:
- import POW
- except Exception:
- pass
-
- NTLM_AUTH_NONE = 1
- NTLM_AUTH_CONNECT = 2
- NTLM_AUTH_CALL = 3
- NTLM_AUTH_PKT = 4
- NTLM_AUTH_PKT_INTEGRITY = 5
- NTLM_AUTH_PKT_PRIVACY = 6
-
- NTLMSSP_KEY_56 = 0x80000000
- NTLMSSP_KEY_EXCHANGE = 0x40000000
- NTLMSSP_KEY_128 = 0x20000000
- # NTLMSSP_ = 0x10000000
- # NTLMSSP_ = 0x08000000
- # NTLMSSP_ = 0x04000000
- # NTLMSSP_ = 0x02000000
- # NTLMSSP_ = 0x01000000
- NTLMSSP_TARGET_INFO = 0x00800000
- # NTLMSSP_ = 0x00400000
- # NTLMSSP_ = 0x00200000
- # NTLMSSP_ = 0x00100000
- NTLMSSP_NTLM2_KEY = 0x00080000
- NTLMSSP_CHALL_NOT_NT = 0x00040000
- NTLMSSP_CHALL_ACCEPT = 0x00020000
- NTLMSSP_CHALL_INIT = 0x00010000
- NTLMSSP_ALWAYS_SIGN = 0x00008000 # forces the other end to sign packets
- NTLMSSP_LOCAL_CALL = 0x00004000
- NTLMSSP_WORKSTATION = 0x00002000
- NTLMSSP_DOMAIN = 0x00001000
- # NTLMSSP_ = 0x00000800
- # NTLMSSP_ = 0x00000400
- NTLMSSP_NTLM_KEY = 0x00000200
- NTLMSSP_NETWARE = 0x00000100
- NTLMSSP_LM_KEY = 0x00000080
- NTLMSSP_DATAGRAM = 0x00000040
- NTLMSSP_SEAL = 0x00000020
- NTLMSSP_SIGN = 0x00000010 # means packet is signed, if verifier is wrong it fails
- # NTLMSSP_ = 0x00000008
- NTLMSSP_TARGET = 0x00000004
- NTLMSSP_OEM = 0x00000002
- NTLMSSP_UNICODE = 0x00000001
-
- class NTLMAuthHeader(Structure):
- commonHdr = (
- ('auth_type', 'B=10'),
- ('auth_level','B'),
- ('auth_pad_len','B=0'),
- ('auth_rsvrd','"\x00'),
- ('auth_ctx_id','<L=747920'),
- )
- structure = (
- ('data',':'),
- )
-
- class NTLMAuthNegotiate(NTLMAuthHeader):
- structure = (
- ('','"NTLMSSP\x00'),
- ('message_type','<L=1'),
- ('flags','<L'),
- ('domain_len','<H-domain_name'),
- ('domain_max_len','<H-domain_name'),
- ('domain_offset','<L'),
- ('host_len','<H-host_name'),
- ('host_maxlen','<H-host_name'),
- ('host_offset','<L'),
- ('host_name',':'),
- ('domain_name',':'))
-
- def __init__(self):
- NTLMAuthHeader.__init__(self)
- self['flags']= (
- NTLMSSP_KEY_128 |
- NTLMSSP_KEY_EXCHANGE|
- # NTLMSSP_LM_KEY |
- NTLMSSP_NTLM_KEY |
- NTLMSSP_UNICODE |
- # NTLMSSP_ALWAYS_SIGN |
- NTLMSSP_SIGN |
- NTLMSSP_SEAL |
- # NTLMSSP_TARGET |
- 0)
- self['host_name']=''
- self['domain_name']=''
-
- def __str__(self):
- self['host_offset']=32
- self['domain_offset']=32+len(self['host_name'])
- return NTLMAuthHeader.__str__(self)
-
- class NTLMAuthChallenge(NTLMAuthHeader):
- structure = (
- ('','"NTLMSSP\x00'),
- ('message_type','<L=2'),
- ('domain_len','<H-domain_name'),
- ('domain_max_len','<H-domain_name'),
- ('domain_offset','<L'),
- ('flags','<L'),
- ('challenge','8s'),
- ('reserved','"\x00\x00\x00\x00\x00\x00\x00\x00'),
- ('domain_name',':'))
-
- class NTLMAuthChallengeResponse(NTLMAuthHeader):
- structure = (
- ('','"NTLMSSP\x00'),
- ('message_type','<L=3'),
- ('lanman_len','<H-lanman'),
- ('lanman_max_len','<H-lanman'),
- ('lanman_offset','<L'),
- ('ntlm_len','<H-ntlm'),
- ('ntlm_max_len','<H-ntlm'),
- ('ntlm_offset','<L'),
- ('domain_len','<H-domain_name'),
- ('domain_max_len','<H-domain_name'),
- ('domain_offset','<L'),
- ('user_len','<H-user_name'),
- ('user_max_len','<H-user_name'),
- ('user_offset','<L'),
- ('host_len','<H-host_name'),
- ('host_max_len','<H-host_name'),
- ('host_offset','<L'),
- ('session_key_len','<H-session_key'),
- ('session_key_max_len','<H-session_key'),
- ('session_key_offset','<L'),
- ('flags','<L'),
- ('domain_name',':'),
- ('user_name',':'),
- ('host_name',':'),
- ('lanman',':'),
- ('ntlm',':'),
- ('session_key',':'))
-
- def __init__(self, username, password, challenge):
- NTLMAuthHeader.__init__(self)
- self['session_key']=''
- self['user_name']=username.encode('utf-16le')
- self['domain_name']='' #"CLON".encode('utf-16le')
- self['host_name']='' #"BETS".encode('utf-16le')
- self['flags'] = ( #authResp['flags']
- # we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using uninitializaed verifiers
- NTLMSSP_KEY_128 |
- NTLMSSP_KEY_EXCHANGE|
- # NTLMSSP_LM_KEY |
- NTLMSSP_NTLM_KEY |
- NTLMSSP_UNICODE |
- # NTLMSSP_ALWAYS_SIGN |
- NTLMSSP_SIGN |
- NTLMSSP_SEAL |
- # NTLMSSP_TARGET |
- 0)
- # Here we do the stuff
- if username and password:
- lmhash = compute_lmhash(password)
- nthash = compute_nthash(password)
- self['lanman']=get_ntlmv1_response(lmhash, challenge)
- self['ntlm']=get_ntlmv1_response(nthash, challenge) # This is not used for LM_KEY nor NTLM_KEY
- else:
- self['lanman'] = ''
- self['ntlm'] = ''
- if not self['host_name']:
- self['host_name'] = 'NULL'.encode('utf-16le') # for NULL session there must be a hostname
-
- def __str__(self):
- self['domain_offset']=64
- self['user_offset']=64+len(self['domain_name'])
- self['host_offset']=self['user_offset']+len(self['user_name'])
- self['lanman_offset']=self['host_offset']+len(self['host_name'])
- self['ntlm_offset']=self['lanman_offset']+len(self['lanman'])
- self['session_key_offset']=self['ntlm_offset']+len(self['ntlm'])
- return NTLMAuthHeader.__str__(self)
-
- class ImpacketStructure(Structure):
- def set_parent(self, other):
- self.parent = other
-
- def get_packet(self):
- return str(self)
-
- def get_size(self):
- return len(self)
-
- class NTLMAuthVerifier(NTLMAuthHeader):
- structure = (
- ('version','<L=1'),
- ('data','12s'),
- # ('_zero','<L=0'),
- # ('crc','<L=0'),
- # ('sequence','<L=0'),
- )
-
- KNOWN_DES_INPUT = "KGS!@#$%"
-
- def __expand_DES_key( key):
- # Expand the key from a 7-byte password key into a 8-byte DES key
- key = key[:7]
- key += '\x00'*(7-len(key))
- s = chr(((ord(key[0]) >> 1) & 0x7f) << 1)
- s = s + chr(((ord(key[0]) & 0x01) << 6 | ((ord(key[1]) >> 2) & 0x3f)) << 1)
- s = s + chr(((ord(key[1]) & 0x03) << 5 | ((ord(key[2]) >> 3) & 0x1f)) << 1)
- s = s + chr(((ord(key[2]) & 0x07) << 4 | ((ord(key[3]) >> 4) & 0x0f)) << 1)
- s = s + chr(((ord(key[3]) & 0x0f) << 3 | ((ord(key[4]) >> 5) & 0x07)) << 1)
- s = s + chr(((ord(key[4]) & 0x1f) << 2 | ((ord(key[5]) >> 6) & 0x03)) << 1)
- s = s + chr(((ord(key[5]) & 0x3f) << 1 | ((ord(key[6]) >> 7) & 0x01)) << 1)
- s = s + chr((ord(key[6]) & 0x7f) << 1)
- return s
-
- def __DES_block(key, msg):
- if POW:
- cipher = POW.Symmetric(POW.DES_ECB)
- cipher.encryptInit(__expand_DES_key(key))
- return cipher.update(msg)
- else:
- cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB)
- return cipher.encrypt(msg)
-
- def ntlmssp_DES_encrypt(key, challenge):
- answer = __DES_block(key[:7], challenge)
- answer += __DES_block(key[7:14], challenge)
- answer += __DES_block(key[14:], challenge)
- return answer
-
- def compute_lmhash(password):
- # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
- password = password.upper()
- lmhash = __DES_block(password[:7], KNOWN_DES_INPUT)
- lmhash += __DES_block(password[7:14], KNOWN_DES_INPUT)
- return lmhash
-
- def compute_nthash(password):
- # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
- password = unicode(password).encode('utf_16le')
- if POW:
- hash = POW.Digest(POW.MD4_DIGEST)
- else:
- hash = MD4.new()
- hash.update(password)
- return hash.digest()
-
- def get_ntlmv1_response(key, challenge):
- return ntlmssp_DES_encrypt(key, challenge)
-
-
-